﻿using System;
using System.IO;
using NUnit.Framework;

namespace DirectoryCleaner.Tests
{
    /// <summary>
    /// Tests for Cleaner.
    /// </summary>
    [TestFixture]
    public class CleanerTest
    {
        /// <summary>
        /// Creates the default file structure used for all tests, and populates them with some dummy files.
        /// </summary>
        [SetUp]
        public void CreateDirectoryAndFileStructure()
        {
            // create directories
            Directory.CreateDirectory("Root");
            Directory.CreateDirectory("Root/Sub1");
            Directory.CreateDirectory("Root/Sub1/Sub1");
            Directory.CreateDirectory("Root/Sub2");

            // populate dirs with files
            using (File.Create("Root/Normal.txt"))
            using (File.Create("Root/Sub1/another.cs"))
            using (File.Create("Root/Sub1/another.xml"))
            using (File.Create("Root/Sub1/Great.txt"))
            using (File.Create("Root/Sub2/index.html"))
            using (File.Create("Root/Sub2/Parser.cs"))
            using (File.Create("Root/Sub1/Sub1/Jokes.txt"))
            using (File.Create("Root/Sub1/Sub1/Film.cs"))
            using (File.Create("Root/Sub1/Sub1/Todo.txt"))
            {
            }
        }

        /// <summary>
        /// Check to make sure the correct exception is thrown when the root directory provided is null.
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DirectoryNotNullTest()
        {
            string[] extensions = { ".txt", ".xml" };
            Cleaner actual = new Cleaner(null, extensions);
        }

        /// <summary>
        /// Check to make sure that the correct exception is thrown when the file extensions to delete
        /// are null.
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void FileExtensionsNullTest()
        {
            Cleaner actual = new Cleaner(Directory.GetCurrentDirectory(), null);
        }

        /// <summary>
        /// Check to make sure that .txt files are preserved.
        /// </summary>
        [Test]
        public void PreserveTextFilesTest()
        {
            string[] extensions = { ".txt" };
            Cleaner actual = new Cleaner("Root", extensions);

            actual.Clean();

            Assert.IsTrue(ExistsFileType("Root", extensions));
        }

        /// <summary>
        /// Check to make sure that when specifying more than one type of file to preserve those files stil exist after
        /// the clean.
        /// </summary>
        [Test]
        public void PreserveTextAndXmlFilesTest()
        {
            string[] extensions = { ".txt", ".xml" };
            Cleaner actual = new Cleaner("Root", extensions);

            actual.Clean();

            Assert.IsTrue(ExistsFileType("Root", extensions));
        }

        /// <summary>
        /// Check to see that the correct exception is thrown when specifying a directory that doesn't exist.
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentException), ExpectedMessage=@"Directory: c:\test does not exist.")]
        public void NoSuchDirectoryTest()
        {
            string[] extensions = { ".txt", ".xml" };
            Cleaner actual = new Cleaner(@"c:\test", extensions);

            actual.Clean();
        }

        /// <summary>
        /// Scans a directory and all it's subdirectories to see if a file with a specified file extension
        /// exists.
        /// </summary>
        /// <param name="rootDirectory">Root directory.</param>
        /// <param name="extensions">File extensions to check for presence of.</param>
        /// <returns>True if a file with the given extension exists; otherwise false.</returns>
        private bool ExistsFileType(string rootDirectory, string[] extensions)
        {
            // check the current dir for the first file with an extension the same as one in extensions
            foreach (string file in Directory.GetFiles(rootDirectory))
            {
                foreach (string ext in extensions)
                {
                    if (ext == Path.GetExtension(file))
                    {
                        return true;
                    }
                }
            }

            // check all subdirectories of the current dir for files with extension
            foreach (string dir in Directory.GetDirectories(rootDirectory))
            {
                return ExistsFileType(dir, extensions);
            }

            return false;
        }
    }
}
